Software programs are continually becoming more complicated. Early programs consisted of straightforward procedural code that presented a simple, command line interface and text display to the user. These simple programs have gradually been replaced with complex programs that have graphical user interfaces and multiple features. As programs have grown in complexity, the amount of effort which is required to write and debug the programs has also increased drastically. Consequently, major efforts have been made to reduce the amount of programming necessary to produce a modern, full-featured product. One of the most successful of these efforts has been the development of object-oriented programming in which programs are designed as collections of discrete elements called "objects". The objects can be modified and reused in many cases, thereby reducing the development effort.
As will be understood by those skilled in the art, objects in the context of object-oriented programming are software entities comprising data and methods or operations on that data. The methods of an object collectively form an interface for manipulating the data in the object. The objects exist only at program runtime and are created, or instantiated, from object "classes" which are actually written by the programmer. The class code written by a programmer can be "reused" by another programmer by instantiating objects from that code.
In order to further reduce the programming burden, distributed object systems have been developed in which methods in objects resident on a server can be executed or invoked remotely over a network from a client application. In this manner, the objects can be developed and maintained by a party different from the party that developed the client application. In such a system information is routed or streamed between the client and the server. This information includes requests from the client to invoke an object on the server and results and data from the method invocation returning from the server to the client. In addition, object-oriented programs often communicate by streaming objects from one program to another.
In such streaming operations, a stream writer organizes, or marshals, the information to form a serial data stream. The serial data stream is then sent to the server where a stream reader unmarshals, the serial data stream to reconstruct a copy of the original information. The stream reader must operate such that the unmarshaling exactly "undoes" the effect of the marshaling so that the original information can be reconstructed. Ordinarily, such an operation does not present a problem, but when the stream reader is not written by the same author as the stream writer there can be incompatibilities.
In order to standardize the marshaling and unmarshaling and data transfer process, an industry consortium called the Object Management Group (OMG) was formed whose mission is to define a set of interfaces for inter-operable software. Its first specification, the Common Object Request Broker Architecture (CORBA) specification, is an industry consensus standard that hides all differences between programming languages, operating systems, and object location. The CORBA standard defines an object request broker (ORB) that handles the marshaling, transport and unmarshaling of information between applications. The ORB functions as a communication infrastructure, transparently relaying object requests across distributed heterogeneous computing environments. Inter-operability is accomplished through well-defined object interface specifications which allow client applications to connect to the ORB. CORBA provides an implementation independent notation for defining interfaces called the OMG Interface Definition Language (IDL).
The OMG CORBA specification defines an implementation independent object model which is actually built with a programming language, such as C++ or Java. In this model CORBA objects (also called "servants"), which are implemented by servers, have references that can be exported to clients. Clients and servers are roles, not mutually exclusive tasks for a single program, so that any one program can be both a client and a server. Objects and object references are typically different programming language objects, although they do not have to be.
Objects may be transient or persistent; a transient object is one for which there is no continuity of state from one process to another. An object's state generally refers to that portion of an object that is not executable code. A transient object is always launched in a state defined by a set of initialization parameters, it is bound to a single process, and its address may not change. In contrast, a persistent object is not bound to a single process, its address may change over time, and there is a continuity of state from one process to another for a persistent object, that is, its state is not defined by a set of initialization parameters at its launching. A transient object may be transformed into a persistent object by persistently storing and retrieving the current version of the object's state so that, upon launching, the object's state will reflect its most recent operations and will not require re-initialization. Persistent objects, therefore, relieve programmers from the onerous task of updating every attribute of every object every time an object is launched.
In one approach to providing persistent objects, a programming language extension provides an interface to the functionality of a database for storing an object's persistent attributes. However, such databases are typically relational databases and relational databases can be a rather awkward mechanism for storing data in the format typically employed for the description of an object's state. Although object oriented databases are available, the objects typically created by object oriented databases are not CORBA objects and so cannot take advantage of the functionality and services provided by the CORBA guidelines.
An approach to storing object data in a distributed object network that is compatible with CORBA guidelines is disclosed in a copending patent application filed on Jul 1, 1996, having Ser. No. 08/677,013 and entitled, "Method and Apparatus For Storing Persistent Object Data On A Distributed Object Network Using A Marshaling Framework", by Ken M. Cavanaugh III, the inventor of the present invention, et al, which is assigned to the same assignee as the present invention and is hereby incorporated by reference in its entirety. That application sets forth means and methods for the persistent storage of an object's state and an index, or dictionary. The combination of stored object states and index constitute an indexed collection of elements, each element of which includes an object's state, which yields a collection of persistent objects.
With an indexed collection such as this, many applications would benefit greatly from a mechanism for listing all the elements in the collection. Such mechanisms are often referred to as iterators. The creation of persistent iterators poses particularly daunting obstacles, especially in multi-threaded distributed object systems. For example, if one thread reads through the elements in a collection and performs some computation on the elements and another thread concurrently deletes elements of the collection, the iterator associated with the first thread could miss some elements of the collection deleted by the second thread. One approach to the implementation of an iterator in a mult-threaded system is to force all other threads that need to access the elements in a collection to wait on a lock while one thread is iterating over the collection. While this approach ensures that elements will not be inadvertently "hidden" from iterators, it exacts high performance penalties. The iterator may require an extremely long time to complete, especially if it is used by a remote application.
A stable iterator, that is, an iterator which always returns to the same set of objects in the same order as existed at the time the iterator was created, regardless of subsequent creation and deletion of objects in the collection by other threads during operation of the iterator, would therefore be highly desirable. The concurrent support of a plurality of stable iterators would be particularly advantageous for a shared data system, such as a distributed object system.